#!/usr/bin/env python
"""

    run_liftover.py
    [--log_file PATH]
    [--quiet]

"""

################################################################################
#
#   run_liftover
#
#
#   Copyright (c) 12/14/2009 Leo Goodstadt
#   
#   Permission is hereby granted, free of charge, to any person obtaining a copy
#   of this software and associated documentation files (the "Software"), to deal
#   in the Software without restriction, including without limitation the rights
#   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#   copies of the Software, and to permit persons to whom the Software is
#   furnished to do so, subject to the following conditions:
#   
#   The above copyright notice and this permission notice shall be included in
#   all copies or substantial portions of the Software.
#   
#   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#   THE SOFTWARE.
#################################################################################



#88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888

#   options        


#88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888

import sys, os
import os.path
import StringIO

# add self to search path for testing
if __name__ == '__main__':
    exe_path = os.path.split(os.path.abspath(sys.argv[0]))[0]
    sys.path.append(os.path.abspath(os.path.join(exe_path,"..", "python_modules")))
    module_name = os.path.split(sys.argv[0])[1]
    module_name = os.path.splitext(module_name)[0];
else:
    module_name = __name__

#88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888

#   imports        


#88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888

import StringIO
import re
import operator

from collections import defaultdict
import logging
from locus import t_locus
from nested_dict import nested_dict
from lg_program_logging import setup_std_logging, MESSAGE
from run_cmd import run_cmd

#88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888

#   Functions        


#88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888


def do_liftover (loci_to_lift, liftover_bin, liftover_working_dir, 
                    chain_file, minSizeQ, step_name, logger, keep_files = True, **queue_parameters) :
    """
    helper function
        set the following parameters to run on queue
            queue_parameters{"queue_cmd_prefix"}
            queue_parameters{"logging_mutex"}
        
    """

    #
    #   write out reference coordinates in preparation for running lifover 
    # 

    loci_to_lift_file_name  = os.path.join(liftover_working_dir, step_name + ".input")
    loci_to_lift_file = open(loci_to_lift_file_name, "w")
    for identifier, loci in loci_to_lift.iteritems():
        for l in loci:
            loci_to_lift_file.write("\t".join(map(str, (l.contig,
                                                        l.beg, l.end, 
                                                        identifier,
                                                        0,      #score
                                                        l.strand))) + "\n")
    loci_to_lift_file.close()
    
        
    results_file = os.path.join(liftover_working_dir, step_name + ".mapped_loci")
    error_file   = os.path.join(liftover_working_dir, step_name + ".unmapped")

    # 
    # create cmd for liftover
    #  
    cmd =   " ".join(   [liftover_bin,
                        "-minMatch=0.01",            
                        "-minSizeT=4000",            
                        "-bedPlus=6",            
                        "-multiple",
                        "-minSizeQ=%s" % minSizeQ,
                        loci_to_lift_file_name,                  
                        chain_file,                  
                        results_file,                 
                        error_file,                  
                        ])
    queue_parameters["job_name"] = step_name
    print cmd    
    run_cmd (cmd, "lift %s" % (step_name), logger = logger, **queue_parameters)
    
    
    # 
    #   read the results and return as list
    # 
    resulting_loci = nested_dict(3, t_locus)
    with open(results_file) as results:
        for line in  results:
            contig, beg, end, identifier, region, strand = line.strip().split("\t")
            beg, end, region = map(int, [beg, end, region])
            # sub region of 0
            resulting_loci[identifier][region][0] = t_locus(contig, strand, beg, end)

    if not keep_files:
        os.unlink(loci_to_lift_file)
        os.unlink(error_file)
        os.unlink(results_file)
        
            
    return resulting_loci
        
    
#_________________________________________________________________________________________
#
#   cache_lifted_genomic_loci
#
#_________________________________________________________________________________________
def run_liftover (  loci_to_lift,                species_src,
                    liftover_bin, liftover_working_dir, 
                    logger,
                    lift_chain_file1, minSizeQ1, species_dest1,                # for phase 1 of liftover
                    lift_chain_file2 = "", minSizeQ2 = "", species_dest2 = "", # optional for phase 2 of liftover
                    **queue_parameters):
    """
    Use liftover to get corresponding loci on another genome.
    Optional run this twice to hop via an intermediate species

    set the following parameters to run on queue
        queue_parameters{"queue_cmd_prefix"}
        queue_parameters{"logging_mutex"}
    """
    if lift_chain_file2:
        logger.log(MESSAGE, "lift loci from %s via %s to %s" % (species_src, 
                                                                species_dest1, 
                                                                species_dest2))
    else:
        logger.log(MESSAGE, "lift loci from %s to %s" % (species_src, 
                                                         species_dest1))
        
    #
    #   run liftover for each species using data in cached liftover data file
    # 
        
    step_name1 = species_src + (".via_" if lift_chain_file2 else ".to_") + species_dest1
    
    lifted_loci = do_liftover (     loci_to_lift, liftover_bin, liftover_working_dir, 
                                    lift_chain_file1, minSizeQ1, step_name1, logger, 
                                    **queue_parameters) 
    

    
    if not lift_chain_file2:
        return lifted_loci
        
    # join up regions and identifiers before running liftover again

    loci_to_lift2 = defaultdict(list)

    # note no sub-region yet
    for (identifier, region, sub_region), locus in lifted_loci.iteritems_flat():
        loci_to_lift2["%s_reg_%s" % (identifier, region)].append(locus)

    step_name2 = species_dest1 + ".to_" + species_dest2
        
    lifted_loci2 = do_liftover ( loci_to_lift2, liftover_bin, liftover_working_dir, 
                                lift_chain_file2, minSizeQ2, step_name2, logger, 
                                **queue_parameters) 

    # split identifier / region => identifier / region / sub-region
    lifted_loci = nested_dict(3, t_locus)
    for (identifier, sub_region), locus in lifted_loci2.iteritems_flat():
        real_identifier, region = identifier.split("_reg_")
        lifted_loci[real_identifier][region][sub_region] = locus

    return lifted_loci
                        
    



#88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888

#   Main logic


#88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888

if __name__ == '__main__':
    pass

